package cloud.tianai.ram.policy.client;

import cloud.tianai.ram.policy.common.model.dto.Action;
import cloud.tianai.ram.policy.client.common.util.RamAnnotationUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: 天爱有情
 * @date 2022/3/24 15:34
 * @Description 用于读取和解析Action
 */
public class ActionHolder implements BeanPostProcessor {


    public static final String SKIP = "skip";
    public static final String AUTO_MATCH = "autoMatch";
    public static final String HIT_THROW_ERROR = "hitThrowError";

    Map<Method, Action> methodActionMap = new ConcurrentHashMap<>(256);

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (AnnotationUtils.isCandidateClass(bean.getClass(), cloud.tianai.ram.policy.client.annotation.Action.class)) {

            ReflectionUtils.doWithMethods(bean.getClass(), m -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(m);
                getAction(bridgedMethod);
            });
        }
        return bean;
    }

    public Collection<Action> actionList() {
        return methodActionMap.values();
    }

    public Action getAction(Method method) {
        Action action = methodActionMap.get(method);
        if (action != null) {
            return action;
        }
        cloud.tianai.ram.policy.client.annotation.Action methodAnn = AnnotationUtils.getAnnotation(method, cloud.tianai.ram.policy.client.annotation.Action.class);
        if (methodAnn == null) {
            return null;
        }
        cloud.tianai.ram.policy.client.annotation.Action classAnn = AnnotationUtils.getAnnotation(method.getDeclaringClass(), cloud.tianai.ram.policy.client.annotation.Action.class);
        action = methodActionMap.computeIfAbsent(method, m -> wrapAction(classAnn, methodAnn));
        return action;
    }


    private Action wrapAction(cloud.tianai.ram.policy.client.annotation.Action classAnn, cloud.tianai.ram.policy.client.annotation.Action methodAnn) {
        String resource = RamAnnotationUtils.getResource(classAnn, methodAnn);
        String action = RamAnnotationUtils.getAction(classAnn, methodAnn);
        boolean skip = RamAnnotationUtils.isSkip(classAnn, methodAnn);
        boolean autoMatch = RamAnnotationUtils.getAutoMatch(classAnn, methodAnn);
        boolean hitThrowError = RamAnnotationUtils.getHitThrowError(classAnn, methodAnn);
        String description = RamAnnotationUtils.getDescription(classAnn, methodAnn);
        Action actionData = new Action(resource, action);
        actionData.setDescription(description);
        actionData.addExpand(SKIP, skip);
        actionData.addExpand(AUTO_MATCH, autoMatch);
        actionData.addExpand(HIT_THROW_ERROR, hitThrowError);
        return actionData;
    }
}
